#include "AIEngine.h"

AIEngine::AIEngine()
{
	board = new Board();
	playerTable[p1] = new Player( p1 );
	playerTable[p2] = new Player( p2 );
	movesList.clear();
    regularMovesListTemp.clear();
    currentPlayer = p1;
    isFinished = false;
    movesJouables.clear();
	INFINITY = 10000;
	initializationScorePattern();
}


AIEngine::~AIEngine()
{
	delete board;
	delete playerTable[p1];
	delete playerTable[p2];
}


//Fction de connection des modules
void AIEngine::connecting( GameEngine* ge )
{
	connect( ge, SIGNAL( askingAIMove(GameEngine*) ), this, SLOT( chooseMove(GameEngine*) ) );
	connect( this, SIGNAL( sendingMove(int,int) ), ge, SLOT( recupMove(int,int) ) );
}
		

//Selectionne le move à jouer (traitement global)
void AIEngine::chooseMove( GameEngine* ge )
{
	initialization(ge);

	int level = 0;
	Move m;
	
	switch( playerTable[idEvaluationPlayer]->getType() )
	{
		case AI_1:
		/************** Random Mode ******************/
			m = randomMove();
			//emit sendingMove( m.getX(), m.getY() );
		/*********************************************/
			break;
		
		case AI_2:
			level = 2;
			break;
		case AI_3:
			level = 5;
			break;
		default:
			level = 1;
			break;
	}
/************* MiniMax Mode ******************/
/*	cptMiniMax = 0;

	cout << "##########################" << endl << "nb moves= " << movesJouables.size() << endl;
	AIResult res = miniMax(5);
	cout << "    Résultat miniMax = " << res.getScore() << endl;
	cout << "    Coup joué : ";
	res.getMove().affichage();
	cout << "cptMiniMax= " << cptMiniMax << endl;
	cout << "##########################" << endl;
	emit sendingMove( res.getMove().getX(), res.getMove().getY() );
*/
/*********************************************/

	if( level != 0 )
	{
/************** AlphaBeta Mode *********************/
//		cout << level << endl;
//		cptAlphaBeta=0;
//		alphabreak = betabreak = 0;
		AIResult alpha, beta;
		alpha.setScore( -INFINITY );
		beta.setScore( INFINITY );
//		cout << "##########################" << endl << "nb moves= " << movesJouables.size() << endl;
		AIResult res = alphaBeta( level, alpha, beta );
//		cout << "    Résultat AlphaBeta = " << res.getScore() << endl;
//		cout << "    Coup joué : ";
//		res.getMove().affichage();
//		cout << "cptAlphaBeta= " << cptAlphaBeta << endl;
//		cout << "  alphaBreak= " << alphabreak << endl << "  betaBreak=" << betabreak << endl;
//		cout << "##########################" << endl;
		//emit sendingMove( res.getMove().getX(), res.getMove().getY() );
		m = res.getMove();
/***************************************************/
	}
	
	emit sendingMove( m.getX(), m.getY() );
}


//Fonction qui initialise le moteur d'IA
void AIEngine::initialization(GameEngine* ge)
{
//	cout << "Entre ds AIEngine::initialization()" << endl;
	*board = *( ge->getBoard() );
	*playerTable[p1] = *( ge->getPlayer(p1) );
	*playerTable[p2] = *( ge->getPlayer(p2) );
	movesList = ge->getMovesList();
	regularMovesListTemp = ge->getRegularMovesListTemp();
	movesJouables.clear();
	currentPlayer = ge->getCurrentPlayer();
	idEvaluationPlayer = currentPlayer;
	movesSavedList.clear();
	movesSavedList = ge->getMovesSavedList();
	numCurrentMove = ge->getNumCurrentMove();
	
	//Initialisation de movesJouables
	for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
	{
    	if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
    	{
			movesJouables.push_back(regularMovesListTemp[i]);	
		}
	}

}

	
//Choisit aléatoirement un coup à jouer
Move AIEngine::randomMove()
{
//	cout << "Entre ds AIEngine::randomMove()" << endl;
//	cout << "currentPlayer = " << currentPlayer << endl;
	
	if( !regularMovesListTemp.empty() )
	{
//		cout << "Liste regularMovesListTemp" << endl;
	    for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
	    {
//	    	regularMovesListTemp[i].affichage();
	    	if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
	    	{
	        	movesJouables.push_back(regularMovesListTemp[i]);	
	    	}
	    }
	    
	    //génération d'un entier aléatoire
	    int num = (int) (0 + ((float) rand() / RAND_MAX * (movesJouables.size()-1 - 0 + 1)));
	    
//	    cout << "\tmovesJouables.size = " << movesJouables.size() << endl;
//	    cout << "\tnum aleatoire = " << num << endl;
	    
//	    cout << "Liste après suppression:" << endl;
//	    for( int i=0 ; i<movesJouables.size() ; i++ )
//	    {
//	    	movesJouables[i].affichage();
//	    }
	    
	    return movesJouables[num];
	}
	else 
	{
		return Move(-1,-1);
	}
}


AIResult AIEngine::miniMax( int depth )
{
	cptMiniMax++;
//	cout << "cptMiniMax=" << cptMiniMax << endl;

	if ( isFinished )  //Si la partie est terminée
	{
		return getScore();
	}
	else if( depth == 0 )  // Si la profondeur max est atteinte
	{
		return evaluateGame();
	}

	AIResult result, bestResult;

	if ( idEvaluationPlayer == playerTable[currentPlayer]->getId() )  // node Max = Program
	{
		bestResult.setScore(-INFINITY);
//		cout << "	movesJouables size: " << movesJouables.size() << endl;
//		affiche_movesJouables();

		for( int i=0 ; i<movesJouables.size() ; i++ )
		{
//			cout << "	movesJouables size 2: " << movesJouables.size() << endl;
//			affiche_movesJouables();
//			cout <<		"	!!!! eval de";
//			movesJouables[i].affichage();

			playMove( movesJouables[i] );  //Joue le coup i
			result = miniMax( depth-1 );
//			cout <<	"	     Score= " << result.getScore() << endl;
			undoLastMove();  //Annule le dernier coup
			if (result.getScore() > bestResult.getScore())
			{
				bestResult.setScore( result.getScore() );
				bestResult.setMove( movesJouables[i] );
//				bestScore = score;
//				bestMove = movesJouables[i];
//				cout << "		bestScore= " << bestResult.getScore() << endl;
//				cout << "		bestMove= ";
//				bestResult.getMove().affichage();
			}
	//******** ??????????????????? ************ -> movesJouable change de taille au dernier tour		
/*			if( i>=movesJouables.size() )
				i = 10000;
*/	//*****************************************
		}
	}
	else  // node MIN = opponent
	{
		bestResult.setScore( INFINITY );
//		cout << "	movesJouables size 3: " << movesJouables.size() << endl;
//		affiche_movesJouables();
		
		for( int i=0 ; i<movesJouables.size() ; i++ )
		{
//			cout << "	movesJouables size 4: " << movesJouables.size() << endl;
//			affiche_movesJouables();
//			cout <<		"	!!!! eval de";
//			movesJouables[i].affichage();

			playMove( movesJouables[i] );  //Jouer le coup i
			result = miniMax( depth-1 );
			undoLastMove();  //Annuler le dernier coup
//			cout <<	"	     Score= " << result.getScore() << endl;
			if( result.getScore() < bestResult.getScore() )
			{
//				bestScore = score;
//				bestMove = movesJouables[i];
				bestResult.setScore( result.getScore() );
				bestResult.setMove( movesJouables[i] );
//				cout << "		bestScore= " << bestResult.getScore() << endl;
//				cout << "		bestMove= ";
//				bestResult.getMove().affichage();
			}
		}
	}
	
	return bestResult ;
}


AIResult AIEngine::getScore()
{
//Retourne le score du joueur faisant l'évaluation, pas forcément le joueur courant
//	cout << "entre ds getScore()" << endl;
	AIResult res;
	res.setScore(playerTable[idEvaluationPlayer]->getScore());
	return res;
}



//Evaluation standard à partir du tabeau 'scorePattern'
AIResult AIEngine::evaluateGame()
{
	int scoreP1 = 0, scoreP2 = 0;
	
	for( int x=0 ; x<8 ; x++ )
	{
		for( int y=0 ; y<8 ; y++ )
		{
			if( board->getTypeSquareBoard(x,y) == Occupied )
			{
				if( board->getColorPawnBoard(x,y) == playerTable[p1]->getColor() )
				{
					scoreP1 += scorePattern[x][y];
				}
				else
				{
					scoreP2 += scorePattern[x][y];
				}
			}
		}
	}
//	cout << "ScoreP1=" << scoreP1 << endl << "ScoreP2= " << scoreP2 << endl;
	AIResult res;
	if( p1 == idEvaluationPlayer )
	{
		res.setScore(scoreP1-scoreP2);
	}
	else
	{
		res.setScore(scoreP2-scoreP1);
	}
	return res;
}



//Evaluation "évolutive" à partir du tableau 'scorePattern'
AIResult AIEngine::evaluateGameEvolutive()
{
	int y,x;
	int scoreP1 = 0, scoreP2 = 0;
	
	/******** Evaluation de base par rapport au pattern de score **********/
	for( x=0 ; x<8 ; x++ )
	{
		for( y=0 ; y<8 ; y++ )
		{
			if( board->getTypeSquareBoard(x,y) == Occupied )
			{
				if( board->getColorPawnBoard(x,y) == playerTable[p1]->getColor() )
				{
					scoreP1 += scorePattern[x][y];
				}
				else
				{
					scoreP2 += scorePattern[x][y];
				}
			}
		}
	}
	/**************************************************************************/
	
	
	/****************** Analyse la structure des bords ************************/
	ColorPawn colorTmp;
	bool rowFull[4];
	for( x=0 ; x<4 ; x++ )
		rowFull[x] = false;
		
	//coin 0,0
	if( board->getTypeSquareBoard(0,0) == Occupied )
	{
		colorTmp = board->getColorPawnBoard(0,0);
		//Bord supérieur -> row 0
		x = 1;
		while( board->getTypeSquareBoard(x,0) == Occupied && x<7 )
		{
			if( board->getColorPawnBoard(x,0) == colorTmp )
			{
				updateScoreEvaluate( x, colorTmp, scoreP1, scoreP2 );
				if( x == 6 ) //row full
				{
					rowFull[0] = true;
				}
				x++;
			}
			else
			{
				x = 7;
			}
		}
		//Bord gauche -> column 0
		y = 1;
		while( board->getTypeSquareBoard(0,y) == Occupied && y<7 )
		{
			if( board->getColorPawnBoard(0,y) == colorTmp )
			{
				updateScoreEvaluate( y, colorTmp, scoreP1, scoreP2 );
				if( y == 6 )
				{
					rowFull[3] = true;
				}
				y++;
			}
			else
			{
				y = 7;
			}
		}

	}

	//coin 7,0
	if( board->getTypeSquareBoard(7,0) == Occupied )
	{
		colorTmp = board->getColorPawnBoard(7,0);
		//Bord supérieur -> row 0
		if( rowFull[0] == false )  //on ne refais pas la ligne si elle est déja remplie par une seule couleur
		{
			x = 6;
			while( board->getTypeSquareBoard(x,0) == Occupied && x>0 )
			{
				if( board->getColorPawnBoard(x,0) == colorTmp )
				{
					updateScoreEvaluate( x, colorTmp, scoreP1, scoreP2 );
					x--;
				}
				else
				{
					x = 0;
				}
			}
		}
		//Bord droit -> column 7
		y = 1;
		while( board->getTypeSquareBoard(7,y) == Occupied && y<7 )
		{
			if( board->getColorPawnBoard(7,y) == colorTmp )
			{
				updateScoreEvaluate( y, colorTmp, scoreP1, scoreP2 );
				if( y == 6 )
				{
					rowFull[1] = true;
				}
				y++;
			}
			else
			{
				y = 7;
			}
		}

	}
	
	//coin 7,7
	if( board->getTypeSquareBoard(7,7) == Occupied )
	{
		colorTmp = board->getColorPawnBoard(7,7);
		//Bord droit -> column 7
		if( rowFull[1] == false )  //on ne refais pas la ligne si elle est déja remplie par une seule couleur
		{
			y = 6;
			while( board->getTypeSquareBoard(7,y) == Occupied && y>0 )
			{
				if( board->getColorPawnBoard(7,y) == colorTmp )
				{
					updateScoreEvaluate( y, colorTmp, scoreP1, scoreP2 );
					y--;
				}
				else
				{
					y = 0;
				}
			}
		}
		//Bord bas -> row 7
		x = 6;
		while( board->getTypeSquareBoard(x,7) == Occupied && x>0 )
		{
			if( board->getColorPawnBoard(x,7) == colorTmp )
			{
				updateScoreEvaluate( x, colorTmp, scoreP1, scoreP2 );
				if( x == 1 )
				{
					rowFull[2] = true;
				}
				x--;
			}
			else
			{
				x = 0;
			}
		}
	}
	
	//coin 0,7
	if( board->getTypeSquareBoard(0,7) == Occupied )
	{
		colorTmp = board->getColorPawnBoard(0,7);
		//Bord inférieur -> row 7
		if( rowFull[2] == false )  //on ne refais pas la ligne si elle est déja remplie par une seule couleur
		{
			x = 0;
			while( board->getTypeSquareBoard(x,7) == Occupied && x<7 )
			{
				if( board->getColorPawnBoard(x,7) == colorTmp )
				{
					updateScoreEvaluate( x, colorTmp, scoreP1, scoreP2 );
					x++;
				}
				else
				{
					x = 7;
				}
			}
		}
		//Bord gauche -> column 0
		if( rowFull[3] == false )
		{
			y = 6;
			while( board->getTypeSquareBoard(0,y) == Occupied && y>0 )
			{
				if( board->getColorPawnBoard(0,y) == colorTmp )
				{
					updateScoreEvaluate( y, colorTmp, scoreP1, scoreP2 );
					y--;
				}
				else
				{
					y = 0;
				}
			}
		}
	}

	//case X 1,1
	if( board->getTypeSquareBoard(1,1) == Occupied && board->getTypeSquareBoard(0,0) == Occupied )
	{
		colorTmp = board->getColorPawnBoard(1,1);
		if( colorTmp == board->getColorPawnBoard(0,0) ) //coin de la même couleur que la case X
		{
			updateScoreEvaluate( 5, colorTmp, scoreP1, scoreP2 );
			if( board->getColorPawnBoard(0,1) == colorTmp && board->getColorPawnBoard(1,0) == colorTmp ) //pion définitif
			{
				updateScoreEvaluate(1, colorTmp, scoreP1, scoreP2);
			}
		}
	}
	//case X 6,1
	if( board->getTypeSquareBoard(6,1) == Occupied && board->getTypeSquareBoard(7,0) == Occupied )
	{
		colorTmp = board->getColorPawnBoard(6,1);
		if( colorTmp == board->getColorPawnBoard(7,0) ) //coin de la même couleur que la case X
		{
			updateScoreEvaluate( 5, colorTmp, scoreP1, scoreP2 );
			if( board->getColorPawnBoard(6,0) == colorTmp && board->getColorPawnBoard(7,1) == colorTmp ) //pion définitif
			{
				updateScoreEvaluate(1, colorTmp, scoreP1, scoreP2);
			}
		}
	}
	//case X 6,6
	if( board->getTypeSquareBoard(6,6) == Occupied && board->getTypeSquareBoard(7,7) == Occupied )
	{
		colorTmp = board->getColorPawnBoard(6,6);
		if( colorTmp == board->getColorPawnBoard(7,7) ) //coin de la même couleur que la case X
		{
			updateScoreEvaluate( 5, colorTmp, scoreP1, scoreP2 );
			if( board->getColorPawnBoard(6,7) == colorTmp && board->getColorPawnBoard(7,6) == colorTmp ) //pion définitif
			{
				updateScoreEvaluate(1, colorTmp, scoreP1, scoreP2);
			}
		}
	}	
	//case X 1,6
	if( board->getTypeSquareBoard(1,6) == Occupied && board->getTypeSquareBoard(0,7) == Occupied )
	{
		colorTmp = board->getColorPawnBoard(1,6);
		if( colorTmp == board->getColorPawnBoard(0,7) ) //coin de la même couleur que la case X
		{
			updateScoreEvaluate( 5, colorTmp, scoreP1, scoreP2 );
			if( board->getColorPawnBoard(0,6) == colorTmp && board->getColorPawnBoard(1,7) == colorTmp ) //pion définitif
			{
				updateScoreEvaluate(1, colorTmp, scoreP1, scoreP2);
			}
		}
	}

	
	/************* Calcul de la valeur de retour ********************/
//	cout << "ScoreP1=" << scoreP1 << endl << "ScoreP2= " << scoreP2 << endl;
	AIResult res;
	if( p1 == idEvaluationPlayer )
	{
		res.setScore(scoreP1-scoreP2);
	}
	else
	{
		res.setScore(scoreP2-scoreP1);
	}
	return res;
}


void AIEngine::updateScoreEvaluate( int square, ColorPawn color, int &scoreP1, int &scoreP2 )
{
	int value;
	switch( square )
	{
		case 1:
		case 6:
			value = 300; //+150 pour annuler le score initial et +150 pr donner le score de la case
			break;
		case 2:
		case 3:
		case 4:
		case 5:
			value = 100; //On ajoute 100 à la valeur initiale
			break;
		default:
			value = 0;
			break;
	}

	if( color == playerTable[p1]->getColor() )
	{
		scoreP1 += value;
	}
	else
	{
		scoreP2 += value;
	}
}



bool AIEngine::playMove(Move m)
{
//Joue le coup sur l'othellier
//MAJ le contenu de 'movesJouables'
    bool ret;   //value returned

    //Récupération et MAJ de la couleur du coup à joué
    m.setColor( playerTable[currentPlayer]->getColor() );
    //Ajout du pion sur l'othellier
    ret = board->addPawn( m.getX(), m.getY(), m.getColor() );

    if( ret )  //Si coup légal alors...
    {
    	initializationSavingMove();  //Initialisation de la liste des coups sauvés

        playerTable[currentPlayer]->increaseScore();  //1 pt en plus pr le pion posé
        addMoveList(m);  //ajout du coup ds la liste
        updateGame(m);  //MAJ des données du jeu

        nextPlayer();  //joueur suivant

        definingRegularMoves();  //Définition des nouveaux 'coups légaux'
		
        if( playerTable[currentPlayer]->getNumMoves() == 0 ) //Si le joueur ne peut pas joué
        {
            nextPlayer();
            if( playerTable[currentPlayer]->getNumMoves() == 0 ) //Aucun joueurs ne peut jouer
            {
                isFinished = true;
            }
        }

        if( !isFinished )
        {
            updateRegularMove();    //MAJ des coups légaux du joueur courant sur l'othellier
//			saveCurrentPlayer();
//			saveRegularMoves();  //Sauvegarde les coups réguliers		
			//MAJ de 'numCurrentMove'
//			numCurrentMove ++;
        }
		saveCurrentPlayer();
		saveRegularMoves();  //Sauvegarde les coups réguliers		
		//MAJ de 'numCurrentMove'
		numCurrentMove ++;

	}
	//Initialisation de movesJouables
	movesJouables.clear();
	for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
	{
    	if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
    	{
			movesJouables.push_back(regularMovesListTemp[i]);	
		}
	}

    return ret;
}



void AIEngine::undoLastMove()
{
	//On annule le coup dc la partie sera forcément non finie
	isFinished = false;
	if( numCurrentMove > 0 )
	{
		Move moveTmp;
	//On se recale sur le coup précédent
		numCurrentMove--;
	//Récupérer le joueur courant
		if( numCurrentMove == 0 ) //Config de départ
		{
			//Le joueur qui a commencé est le joueur qui a les pions noirs
			if( playerTable[p1]->getColor() == Black )
			{
				currentPlayer = p1;
			}
			else
			{
				currentPlayer = p2;
			}
		}
		else
		{
			currentPlayer = movesSavedList[numCurrentMove-1].getCurrentPlayer();
		}
//-->envoie msg 'joueur courant' à l'interface
	//Retirer le dernier pion posé		
		board->emptySquare(movesList[numCurrentMove].getX(),movesList[numCurrentMove].getY());
		playerTable[currentPlayer]->decreaseScore();  //MAJ des scores
	//MAJ dernier coup sur le plateau si il existe
		if(numCurrentMove > 0)
		{
			board->enableLastMoveSquare(movesList[numCurrentMove-1].getX(),movesList[numCurrentMove-1].getY());
		}
	//Retourner les pions retournés
		for( int i=0 ; i<movesSavedList[numCurrentMove].getSizePawnsTurnedDownList() ; i++ )
		{
			moveTmp = movesSavedList[numCurrentMove].getPawnsTurnedDownList(i);
			board->turnDownPawn(moveTmp.getX(),moveTmp.getY());
			//MAJ des scores
			if( currentPlayer == p1 )
			{
				playerTable[p1]->decreaseScore();
				playerTable[p2]->increaseScore();
			}
			else
			{
				playerTable[p1]->increaseScore();
				playerTable[p2]->decreaseScore();
			}
		}
		board->clearAnimation();  //Pas d'animation
	//MAJ des coups légaux
		board->clearRegularMove();
		regularMovesListTemp.clear();
		int numMovesCurPlayer = 0;
		//Récupération des coups réguliers ds 'regularMovesListTemp'
		if( numCurrentMove == 0 ) //Configuration de départ
		{
			regularMovesListTemp.clear();
			regularMovesListTemp.push_back( Move(2,3,Black) );
			regularMovesListTemp.push_back( Move(3,2,Black) );
			regularMovesListTemp.push_back( Move(4,5,Black) );
			regularMovesListTemp.push_back( Move(5,4,Black) );
			regularMovesListTemp.push_back( Move(5,3,White) );
			regularMovesListTemp.push_back( Move(4,2,White) );
			regularMovesListTemp.push_back( Move(2,4,White) );
			regularMovesListTemp.push_back( Move(3,5,White) );
		}
		else
		{
			regularMovesListTemp = movesSavedList[numCurrentMove-1].getRegularMovesList();
		}
		//MAJ coups réguliers sur le plateau
		for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
		{
			if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
			{
				board->addRegularMove( regularMovesListTemp[i].getX(), regularMovesListTemp[i].getY() );
				numMovesCurPlayer++;
			}
		}
		
		if( currentPlayer == p1 )
		{
			playerTable[p1]->setNumMoves(numMovesCurPlayer);
			playerTable[p2]->setNumMoves(regularMovesListTemp.size()-numMovesCurPlayer);
		}
		else
		{
			playerTable[p1]->setNumMoves(regularMovesListTemp.size()-numMovesCurPlayer);
			playerTable[p2]->setNumMoves(numMovesCurPlayer);
		}

		//Initialisation de movesJouables
		movesJouables.clear();
		for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
		{
			if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
			{
				movesJouables.push_back(regularMovesListTemp[i]);	
			}
		}
		
	}
}



bool AIEngine::updateGame(Move m)
{
    updateRow(m);
    updateColumn(m);
    updateDiagonal(m);
}


//MAJ des pions de la ligne du coup joué
void AIEngine::updateRow(Move m)
{
    //Récupération coord du coup
    int xMove = m.getX(),
        yMove = m.getY();
    //Récupération de la couleur
    ColorPawn colorMove = m.getColor();

    int i; //indice de parcours


/*--------------- Vérification à la GAUCHE du coup 'm' ---------------------*/
    i = xMove-1;
    /*On se décale à gauche tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i>=0 && board->getTypeSquareBoard(i,yMove)==Occupied && board->getColorPawnBoard(i,yMove)!=colorMove )
    {
        i--;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i>=0 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,yMove)==Occupied && board->getColorPawnBoard(i,yMove)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i++;//On se recale sur la première case adverse (la première à la droite...)
            while( i<xMove )
            {
//                board->turnDownPawn(i,yMove);  //Retournement du pion
				turnDownPawn(i,yMove);  //retournement du pion
                this->updateScore();  //On adapte les scores
                i++;  //On passe à la case suivante à droite
            }
        }
    }

/*--------------- Vérification à la DROITE du coup 'm' ---------------------*/
    i = xMove+1;
    /*On se décale à droite tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i<8 && board->getTypeSquareBoard(i,yMove)==Occupied && board->getColorPawnBoard(i,yMove)!=colorMove )
    {
        i++;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i<8 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,yMove)==Occupied && board->getColorPawnBoard(i,yMove)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i--;//On se recale sur la première case adverse (la première à la gauche...)
            while( i>xMove )
            {
//                board->turnDownPawn(i,yMove);  //Retournement du pion
				turnDownPawn(i,yMove);
                this->updateScore();  //On adapte les scores
                i--;  //On passe à la case suivante à gauche
            }
        }
    }
}


//MAJ des pions de la colonne du coup joué
void AIEngine::updateColumn(Move m)
{
    //Récupération coord du coup
    int xMove = m.getX(),
        yMove = m.getY();
    //Récupération de la couleur
    ColorPawn colorMove = m.getColor();

    int i; //indice de parcours


/*--------------- Vérification au DESSUS du coup 'm' ---------------------*/
    i = yMove-1;
    /*On se décale en haut tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i>=0 && board->getTypeSquareBoard(xMove,i)==Occupied && board->getColorPawnBoard(xMove,i)!=colorMove )
    {
        i--;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i>=0 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(xMove,i)==Occupied && board->getColorPawnBoard(xMove,i)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i++;//On se recale sur la première case adverse (la première en dessous...)
            while( i<yMove )
            {
//                board->turnDownPawn(xMove,i);  //Retournement du pion
				turnDownPawn(xMove,i);
                this->updateScore();  //On adapte les scores
                i++;  //On passe à la case suivante en dessous
            }
        }
    }

/*--------------- Vérification en DESSOUS du coup 'm' ---------------------*/
    i = yMove+1;
    /*On se décale à droite tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i<8 && board->getTypeSquareBoard(xMove,i)==Occupied && board->getColorPawnBoard(xMove,i)!=colorMove )
    {
        i++;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i<8 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(xMove,i)==Occupied && board->getColorPawnBoard(xMove,i)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i--;//On se recale sur la première case adverse (la première au dessus...)
            while( i>yMove )
            {
//                board->turnDownPawn(xMove, i);  //Retournement du pion
                turnDownPawn(xMove,i);
                this->updateScore();  //On adapte les scores
                i--;  //On passe à la case suivante à gauche
            }
        }
    }
}


//MAJ des pions des diagonales du coup joué
void AIEngine::updateDiagonal(Move m)
{
    //Récupération coord du coup
    int xMove = m.getX(),
        yMove = m.getY();
    //Récupération de la couleur
    ColorPawn colorMove = m.getColor();

    int i,j; //indices de parcours


/*--------------- Vérification diagonale HAUT-GAUCHE du coup 'm' ---------------------*/
    i = xMove-1;
    j = yMove-1;
    /*On se décale en haut-gauche tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i>=0 && j>=0 && board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)!=colorMove )
    {
        i--;
        j--;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i>=0 && j>=0 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i++; j++;//On se recale sur la première case adverse (la première en bas-droite...)
            while( i<xMove && j<yMove )
            {
//                board->turnDownPawn(i,j);  //Retournement du pion
  				turnDownPawn(i,j);
                this->updateScore();  //On adapte les scores
                i++; j++; //On passe à la case suivante en bas-droite
            }
        }
    }

/*--------------- Vérification en BAS-DROITE du coup 'm' ---------------------*/
    i = xMove+1;
    j = yMove+1;

    /*On se décale en bas-droite tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i<8 && j<8 && board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)!=colorMove )
    {
        i++;
        j++;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i<8 && j<8 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i--;  j--;//On se recale sur la première case adverse (la première en haut-gauche...)
            while( i>xMove && j>yMove )
            {
//                board->turnDownPawn(i, j);  //Retournement du pion
                turnDownPawn(i,j);
                this->updateScore();  //On adapte les scores
                i--;  j--;//On passe à la case suivante en haut-gauche
            }
        }
    }

/*--------------- Vérification diagonale HAUT-DROITE du coup 'm' ---------------------*/
    i = xMove+1;
    j = yMove-1;
    /*On se décale en haut-droite tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i<8 && j>=0 && board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)!=colorMove )
    {
        i++;
        j--;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i<8 && j>=0 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i--; j++;//On se recale sur la première case adverse (la première en bas-gauche...)
            while( i>xMove && j<yMove )
            {
//                board->turnDownPawn(i,j);  //Retournement du pion
                turnDownPawn(i,j);
                this->updateScore();  //On adapte les scores
                i--; j++; //On passe à la case suivante en bas-gauche
            }
        }
    }

/*--------------- Vérification en BAS-GAUCHE du coup 'm' ---------------------*/
    i = xMove-1;
    j = yMove+1;

    /*On se décale en bas-gauche tant que l'on est encore ds le plateau ET que la case contienne un pion adverse*/
    while( i>=0 && j<8 && board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)!=colorMove )
    {
        i--;
        j++;
    }
    /*On vérifie si on est encore dans le plateau*/
    if( i>=0 && j<8 )
    {
        /*On vérifie si la case contient un pion du joueur*/
        if ( board->getTypeSquareBoard(i,j)==Occupied && board->getColorPawnBoard(i,j)==colorMove )
        {
            /*Des pions adverses sont encadrés, on peut retourner ts les pions jusqu'à la case du coup joué*/
            i++;  j--;//On se recale sur la première case adverse (la première en haut-droite...)
            while( i<xMove && j>yMove )
            {
//                board->turnDownPawn(i, j);  //Retournement du pion
                turnDownPawn(i,j);
                this->updateScore();  //On adapte les scores
                i++;  j--;//On passe à la case suivante en haut-droite
            }
        }
    }
}


void AIEngine::updateScore()
{
    if( currentPlayer == p1 )
    {
        playerTable[p1]->increaseScore();
        playerTable[p2]->decreaseScore();
    }
    else
    {
        playerTable[p1]->decreaseScore();
        playerTable[p2]->increaseScore();
    }
}


void AIEngine::turnDownPawn(int x, int y)
{
	board->turnDownPawn(x,y);
	savePawnTurnedDown(x,y);
}


void AIEngine::definingRegularMoves()
/*Parcours le plateau de jeu et compte le nb de coups légaux pr chaques joueurs*/
{
    ColorPawn colorTmp;
    bool WhiteRegularMove = false,  //permet de ne pas compter un coup légal plusieurs fois pr un joueur...
         BlackRegularMove = false;

    //RAZ des coups légaux de chaques joueurs
    playerTable[p1]->RazNumMoves();
    playerTable[p2]->RazNumMoves();
    //RAZ de la liste de coups légaux
    regularMovesListTemp.clear();


    /************ Calcul des coups légaux du plateau ********/
    for( int y=0 ; y<8 ; y++ )
    {
        for( int x=0 ; x<8 ; x++ )
        {

/*********** Parcours chaque cases du plateau ********************/

            //Si la case est vide = Coup légal potentiel
            if( board->getTypeSquareBoard(x,y)==Empty )
            {

                //RAZ des indicateurs de coup légaux pr la case
                BlackRegularMove = false;
                WhiteRegularMove = false;


/*********** Parcours des cases voisines *********************/
                for( int j=-1 ; j<2 ; j++ )
                {

                    if( (y+j)>=0 && (y+j)<8 )  //si on est ds le tableau
                    {
                        for( int i=-1 ; i<2 ; i++ )
                        {
                            if( (x+i)>=0 && (x+i)<8 )  //si on est ds le tableau
                            {

                                if( !(i==0 && j==0) )  //On ne check pas la case elle-même
                                {

                                    //Vérifie si la case est un coup légal pour la ligne de vecteur (i,j)
                                    if( checkRegularMove(x, y, i, j) )
                                    {
                                        //Récupération de la couleur des pions encadrés
                                        colorTmp = board->getColorPawnBoard(x+i,y+j);
                                        //Si les pions encadrés st blans ET que les noirs n'ont encore pas de coup légal sur cette case
                                        if( colorTmp == White && !BlackRegularMove )
                                        {
                                            //Coup légal NOIR
                                            BlackRegularMove = true;
                                            increaseRegularMove(Black);
                                            //Ajout du coup légal ds la liste temporaire
                                            regularMovesListTemp.push_back( Move(x,y,Black) );
                                        }
                                        //Si les pions encadrés st blacks ET que les blans n ont encore pas de coup légal sur cette case
                                        else if( colorTmp == Black && !WhiteRegularMove )
                                        {
                                            //Coup légal BLANC
                                            WhiteRegularMove = true;
                                            increaseRegularMove(White);
                                            //Ajout du coup légal ds la liste temporaire
                                            regularMovesListTemp.push_back( Move(x,y,White) );
                                        }

                                        //Vérifie si les 2 couleurs ont un coup légal sur cette case
                                        //Auquel cas c est terminé pour cette case
                                        if( BlackRegularMove && WhiteRegularMove )
                                        {
                                            i=2;  j=2;  //Interruption des boucles for...
                                        }
                                    }
                                }

                            }
                        }
                    }

                }  //Fin parcours des cases voisines

            }
        }
    }  //Fin parcours du plateau
}



//MAJ des coups légaux contenu ds 'regularMovesList' sur l'othellier
void AIEngine::updateRegularMove()
{
    for( int i=0 ; i<regularMovesListTemp.size() ; i++ )
    {
        if( regularMovesListTemp[i].getColor() == playerTable[currentPlayer]->getColor() )
        {
            board->addRegularMove( regularMovesListTemp[i].getX(), regularMovesListTemp[i].getY() );
        }
    }
}


void AIEngine::increaseRegularMove(ColorPawn color)
{
    if( playerTable[p1]->getColor() == color )
    {
        playerTable[p1]->increaseRegularMove();
    }
    else
    {
        playerTable[p2]->increaseRegularMove();
    }
}



/*Vérification d'un coup légal suivant plusieurs paramètres...
  Vérifie si les cases du plateau (à partir de la case [squareX,squareY]) selon la ligne de vecteur
  (i,j) représente une configuration pour un coup légal.*/
bool AIEngine::checkRegularMove(int squareX, int squareY, int i, int j)
{
    bool ret = false,  //value returned
         done = false; //end of boucle
    int x = squareX + i,
        y = squareY + j;

    //Vérifie si la case suivante est occupée
    if( board->getTypeSquareBoard(x,y)==Occupied )
    {
        ColorPawn colorTmp = board->getColorPawnBoard(x,y);
        x += i;
        y += j;
        while( x>=0 && x<8 && y>=0 && y<8 && !done)
        {
            if( board->getTypeSquareBoard(x,y)==Occupied )  //Si case occupée
            {
                if( board->getColorPawnBoard(x,y)==colorTmp )
                {
                    x += i;
                    y += j;
                }
                else  //Pion de l autre couleur, dc coup légal
                {
                    ret = true;
                    done = true;
                }
            }
            else  //Case vide dc pas de coup légal
            {
                done = true;
            }
        }
    }
    return ret;
}


void AIEngine::initializationScorePattern()
{
	for( int x=0 ; x<8 ; x++ )
		for( int y=0 ; y<8 ; y++ )
			scorePattern[x][y] = 0;

	//Coins
	scorePattern[0][0]=500;  scorePattern[0][7]=500;  scorePattern[7][0]=500;  scorePattern[7][7]=500;
	
	scorePattern[1][1]=-250;  scorePattern[1][6]=-250;  scorePattern[6][1]=-250;  scorePattern[6][6]=-250;
	
	scorePattern[0][1]=-150;  scorePattern[0][6]=-150;  scorePattern[1][0]=-150;  scorePattern[1][7]=-150;
	scorePattern[6][0]=-150;  scorePattern[6][7]=-150;  scorePattern[7][1]=-150;  scorePattern[7][6]=-150;
	
	scorePattern[0][2]=30;  scorePattern[0][5]=30;  scorePattern[2][0]=30;  scorePattern[2][7]=30;
	scorePattern[5][0]=30;  scorePattern[5][7]=30;  scorePattern[7][2]=30;  scorePattern[7][5]=30;
	
	scorePattern[0][3]=10;  scorePattern[0][4]=10;  scorePattern[3][0]=10;  scorePattern[3][7]=10;
	scorePattern[4][0]=10;  scorePattern[4][7]=10;  scorePattern[7][3]=10;  scorePattern[7][4]=10;
	
	scorePattern[3][3]=16;  scorePattern[3][4]=16;  scorePattern[4][3]=16;  scorePattern[4][4]=16;
	
	scorePattern[3][2]=2;  scorePattern[4][2]=2;  scorePattern[3][5]=2;  scorePattern[4][5]=2;
	scorePattern[2][3]=2;  scorePattern[2][4]=2;  scorePattern[5][3]=2;  scorePattern[5][4]=2;
	
	scorePattern[2][2]=1;  scorePattern[2][5]=1;  scorePattern[5][2]=1;  scorePattern[5][5]=1;
}


void AIEngine::initializationSavingMove()
{
	if( movesSavedList.size() != numCurrentMove )  //Si le vector contient plus de coup que le numéro du coup courrant
	{
		//Suppression des coups supplémentaires
		movesSavedList.erase(movesSavedList.begin()+numCurrentMove, movesSavedList.end() );
	}
	//Ajout d'un InfosMoves à la fin
	movesSavedList.push_back( InfosMoves() );
}


void AIEngine::addMoveList(Move m)
{
	//Si numCurrentMove ne correspond pas au dernier coup joué, on supprime les coups
	if( numCurrentMove != movesList.size() )
	{
		movesList.erase( movesList.begin()+numCurrentMove, movesList.end() );
	}
	//MAJ du numéro du coup joué
	m.setNumMove( numCurrentMove + 1 );
	//Ajoute le coup à la fin de la liste
	movesList.push_back(m);
}


void AIEngine::nextPlayer()
{
    if( currentPlayer == p1 )
    {
        currentPlayer = p2;
    }
    else
    {
        currentPlayer = p1;
    }
}

void AIEngine::saveCurrentPlayer()
{
	movesSavedList[numCurrentMove].saveCurrentPlayer(currentPlayer);
}


//Sauvegarde la liste des coups réguliers du coup courrant
void AIEngine::saveRegularMoves()
{
	movesSavedList[numCurrentMove].saveRegularMoves(regularMovesListTemp);
}


void AIEngine::savePawnTurnedDown(int x, int y)
{
	movesSavedList[numCurrentMove].addPawnsTurnedDown( Move(x,y) );
}


void AIEngine::affiche_movesJouables()
{
	cout << "	*** MovesJouables: " << endl;
	for( int i=0 ; i<movesJouables.size() ; i++ )
	{
		movesJouables[i].affichage();
	}
}


AIResult AIEngine::alphaBeta(int depth, AIResult alpha, AIResult beta)
{
	cptAlphaBeta++;
//	cout << "cptAlphaBeta=" << cptAlphaBeta << endl;

	if ( isFinished )  //Si la partie est terminée
	{
		return getScore();
	}
	else if( depth == 0 )  // Si la profondeur max est atteinte
	{
		return evaluateGameEvolutive();
	}

	AIResult result;
	if( idEvaluationPlayer == playerTable[currentPlayer]->getId() )  // node MAX = Program
	{
//		cout << "	movesJouables size: " << movesJouables.size() << endl;
//		affiche_movesJouables();
		for ( int i=0 ; i<movesJouables.size() ; i++ )
		{
//			cout <<		"	!!!! eval de";
//			movesJouables[i].affichage();

			playMove( movesJouables[i] );  //Jouer le coup i
			result = alphaBeta( depth - 1, alpha, beta );
			undoLastMove();  //Annuler le dernier coup

//			cout <<	"	     Score= " << result.getScore() << endl;

			if( result.getScore() > alpha.getScore() )
			{
				alpha.setScore( result.getScore() );
				alpha.setMove( movesJouables[i] );
//				cout << "		AlphaScore= " << alpha.getScore() << endl;
//				cout << "		AlphaMove= ";
//				alpha.getMove().affichage();

				if( alpha.getScore() >= beta.getScore() )  // alpha break
				{
//					cout << "-------- Alpha Break ------------" << endl;
					alphabreak++;
					break;
				}
			}
		}
		
		return alpha ;
	}
	else  // node MIN = opponent
	{
//		cout << "	movesJouables size: " << movesJouables.size() << endl;
//		affiche_movesJouables();

		for ( int i=0 ; i<movesJouables.size() ; i++ )
		{
//			cout <<		"	!!!! eval de";
//			movesJouables[i].affichage();

			playMove( movesJouables[i] );  //Jouer le coup i
			result = alphaBeta( depth - 1, alpha, beta );
			undoLastMove();  //Annuler le dernier coup

//			cout <<	"	     Score= " << result.getScore() << endl;

			if( result.getScore() < beta.getScore() )
			{
				beta.setScore( result.getScore() );
				beta.setMove( movesJouables[i] );
//				cout << "		BetaScore= " << beta.getScore() << endl;
//				cout << "		BetaMove= ";
//				beta.getMove().affichage();

				if( alpha.getScore() >= beta.getScore() )  // beta break
				{
//					cout << "-------- Beta Break ------------" << endl;
					betabreak++;
					break;
				}
			}
		}
		return beta;
	}
}
